/*
堆排序（Heapsort）是指利用堆这种数据结构所设计的一种排序算法。
堆积是一个近似完全二叉树的结构，并同时满足堆积的性质：
即子结点的键值或索引总是小于（或者大于）它的父节点。
堆排序可以说是一种利用堆的概念来排序的选择排序。

分为两种方法：
大顶堆：每个节点的值都大于或等于其子节点的值，在堆排序算法中用于升序排列；
小顶堆：每个节点的值都小于或等于其子节点的值，在堆排序算法中用于降序排列；

堆排序的平均时间复杂度为 Ο(nlogn)。

算法步骤
    a.创建一个堆 H[0……n-1]；
    b.把堆首（最大值）和堆尾互换；
    c.把堆的尺寸缩小 1，并调用 shift_down(0)，目的是把新的数组顶端数据调整到相应位置；
    d.重复步骤 2，直到堆的尺寸为 1。
 */
let globalLength

/**
 * 构建大顶堆
 */
function _buildMaxHeap(arr) {
    for (let i = Math.floor(globalLength / 2); i >= 0; i--) {
        _heapify(arr, i)
    }
}

/**
 * 堆调整
 * @param arr
 * @param i
 */
function _heapify(arr, i) {
    let largest = i
    const left = 2 * i + 1, right = left + 1

    if (left < globalLength && arr[left] > arr[largest]) {
        largest = left
    }
    if (right < globalLength && arr[right] > arr[largest]) {
        largest = right
    }
    if (largest !== i) {
        _swap(arr, i, largest)
        _heapify(arr, largest)
    }
}

/**
 * 将数组中下标i与下标j的值互换
 * @param arr
 * @param i
 * @param j
 */
function _swap(arr, i, j) {
    const temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp
}

function heapSort(arr) {
    globalLength = arr.length

    _buildMaxHeap(arr)

    for (let i = arr.length - 1; i > 0; i--) {
        _swap(arr, 0, i)
        globalLength--
        _heapify(arr, 0)
    }

    return arr
}

console.log(heapSort([9, 1, 5, 4, 12, 33, 0]))
console.log(heapSort([9, 1, 5, 4, 12, 33, 0, 5]))
console.log(heapSort([9, 1, 5, 4, 12, 33, 0, 12.2, 2.5, 5.3, 4]))

// [ 0, 1, 4, 5, 9, 12, 33 ]
// [ 0, 1, 4, 5, 5, 9, 12, 33 ]
// [ 0, 1, 2.5, 4, 4, 5, 5.3, 9, 12, 12.2, 33 ]
